package com.juhui.file.service;

import com.alibaba.nacos.common.utils.IoUtils;
import com.juhui.file.config.MinioConfig;
import com.juhui.file.enums.PolicyType;
import com.juhui.file.utils.FileUploadUtils;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.SetBucketPolicyArgs;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;

/**
 * Minio 文件存储
 *
 * @author melorogee
 */
@Slf4j
@Service
public class MinioSysFileServiceImpl implements ISysFileService {
	@Autowired
	private MinioConfig minioConfig;

	@Autowired
	private MinioClient client;

	/**
	 * 本地文件上传接口
	 *
	 * @param file 上传的文件
	 * @return 访问地址
	 * @throws Exception
	 */
	@Override
	public String uploadFile(MultipartFile file) throws Exception {
		createBucket();
		String fileName = FileUploadUtils.extractFilename(file);
		InputStream inputStream = file.getInputStream();
		PutObjectArgs args = PutObjectArgs.builder()
				.bucket(minioConfig.getBucketName())
				.object(fileName)
				.stream(inputStream, file.getSize(), -1)
				.contentType(file.getContentType())
				.build();
		client.putObject(args);
		IoUtils.closeQuietly(inputStream);
		return minioConfig.getOutUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
	}

	@Override
	public void delete(String path) {
		path = path.replace(minioConfig.getOutUrl() + "/" + minioConfig.getBucketName() + "/", "");
		try {
			client.removeObject(RemoveObjectArgs.builder()
					.bucket(minioConfig.getBucketName())
					.object(path)
					.build());
		} catch (Exception e) {
			log.error("删除文件失败", e);
		}
	}

	private void createBucket() {
		try {
			String bucketName = minioConfig.getBucketName();
			boolean exists = client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
			if (exists) {
				return;
			}
			// 不存在就创建桶
			client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
			client.setBucketPolicy(SetBucketPolicyArgs.builder()
					.bucket(bucketName)
					.config(getPolicy(bucketName, PolicyType.READ))
					.build());
		} catch (Exception e) {
			log.error("创建Bucket失败, 请核对Minio配置信息:[" + e.getMessage() + "]", e);
		}
	}

	private String getPolicy(String bucketName, PolicyType policyType) {
		StringBuilder builder = new StringBuilder();
		builder.append("{\n");
		builder.append("    \"Statement\": [\n");
		builder.append("        {\n");
		builder.append("            \"Action\": [\n");
		if (policyType == PolicyType.WRITE) {
			builder.append("                \"s3:GetBucketLocation\",\n");
			builder.append("                \"s3:ListBucketMultipartUploads\"\n");
		} else if (policyType == PolicyType.READ_WRITE) {
			builder.append("                \"s3:GetBucketLocation\",\n");
			builder.append("                \"s3:ListBucket\",\n");
			builder.append("                \"s3:ListBucketMultipartUploads\"\n");
		} else {
			builder.append("                \"s3:GetBucketLocation\"\n");
		}
		builder.append("            ],\n");
		builder.append("            \"Effect\": \"Allow\",\n");
		builder.append("            \"Principal\": \"*\",\n");
		builder.append("            \"Resource\": \"arn:aws:s3:::");
		builder.append(bucketName);
		builder.append("\"\n");
		builder.append("        },\n");
		if (PolicyType.READ.equals(policyType)) {
			builder.append("        {\n");
			builder.append("            \"Action\": [\n");
			builder.append("                \"s3:ListBucket\"\n");
			builder.append("            ],\n");
			builder.append("            \"Effect\": \"Deny\",\n");
			builder.append("            \"Principal\": \"*\",\n");
			builder.append("            \"Resource\": \"arn:aws:s3:::");
			builder.append(bucketName);
			builder.append("\"\n");
			builder.append("        },\n");
		}
		builder.append("        {\n");
		builder.append("            \"Action\": ");
		switch (policyType) {
			case WRITE:
				builder.append("[\n");
				builder.append("                \"s3:AbortMultipartUpload\",\n");
				builder.append("                \"s3:DeleteObject\",\n");
				builder.append("                \"s3:ListMultipartUploadParts\",\n");
				builder.append("                \"s3:PutObject\"\n");
				builder.append("            ],\n");
				break;
			case READ_WRITE:
				builder.append("[\n");
				builder.append("                \"s3:AbortMultipartUpload\",\n");
				builder.append("                \"s3:DeleteObject\",\n");
				builder.append("                \"s3:GetObject\",\n");
				builder.append("                \"s3:ListMultipartUploadParts\",\n");
				builder.append("                \"s3:PutObject\"\n");
				builder.append("            ],\n");
				break;
			default:
				builder.append("\"s3:GetObject\",\n");
				break;
		}
		builder.append("            \"Effect\": \"Allow\",\n");
		builder.append("            \"Principal\": \"*\",\n");
		builder.append("            \"Resource\": \"arn:aws:s3:::");
		builder.append(bucketName);
		builder.append("/*\"\n");
		builder.append("        }\n");
		builder.append("    ],\n");
		builder.append("    \"Version\": \"2012-10-17\"\n");
		builder.append("}\n");
		return builder.toString();
	}

}
